﻿using HalconDotNet;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
using DetectApp;
using System.Runtime.CompilerServices;
using NPOI.SS.Formula;
using NPOI.SS.Formula.Functions;
using System.Linq;
using System.Windows.Shapes;
using Microsoft.EntityFrameworkCore.Diagnostics;
using static System.Net.Mime.MediaTypeNames;
using Org.BouncyCastle.Asn1.X9;
using NPOI.SS.UserModel;
using System.Net;


namespace DetectApp.Display
{
    /// <summary>
    /// CDisplayControl.xaml 的交互逻辑
    /// </summary>
    public partial class CDisplayControl : UserControl
    {
        public static readonly DependencyProperty DispImageProperty =
           DependencyProperty.Register("DispImage", typeof(ImageSource), typeof(CDisplayControl));


        public static readonly DependencyProperty WindowTitleProperty =
            DependencyProperty.Register("WindowTitle", typeof(string), typeof(CDisplayControl));

        public bool AllowMoveScale = true;

        private Action<List<LineControl>, string> _actionDrawOver;

        private Action<string> _actionDrawOver2;
        private bool _isMove = false;

        private Stopwatch _regionWatch = Stopwatch.StartNew();
        private ScaleTransform _scaleTransform;

        private Point _startMovePoint;

        private Stopwatch _textWatch = Stopwatch.StartNew();
        private TransformGroup _transformGroup;

        private TranslateTransform _translate;

        private WriteableBitmap? _writeabBitmap;

        private int _index;
        private string _guid;
        public bool CanDraw { get; set; } = false;
        public List<MeasureResult> MeasureResults { get; set; }
        private List<LineControl> _rOIs;
        private string _regionGuid;
        public CDisplayControl()
        {
            InitializeComponent();
            _translate = new TranslateTransform();
            _scaleTransform = new ScaleTransform();
            _transformGroup = new TransformGroup();
            _rOIs = new List<LineControl>();
            _transformGroup.Children.Add(_scaleTransform);
            _transformGroup.Children.Add(_translate);
            CvDisplay.RenderTransform = _transformGroup;
            CvDisplay1.RenderTransform = _transformGroup;
            CvDisplay2.RenderTransform = _transformGroup;
        }

        public Visibility CameraInfoShow { get; set; } = Visibility.Collapsed;

        public ImageSource DispImage
        {
            get { return (ImageSource)GetValue(DispImageProperty); }
            set { SetValue(DispImageProperty, value); }
        }
        /// <summary>
        /// 获取绘制ROIControl的画板
        /// </summary>
        public Canvas GetCanvas { get => CvDisplay2; }
        public Visibility ImageInfoShow { get; set; } = Visibility.Visible;

        /// <summary>
        /// 流程号
        /// </summary>
        public int ProgNo { get; set; }



        public void RegisterDraw(Action<List<LineControl>, string> action, int index, string guid)
        {
            this._actionDrawOver = action;
            this._index = index;
            _guid = guid;
        }

        public void RegisterDraw(Action< string> action, int index, string guid)
        {
            this._actionDrawOver2 = action;
            this._index = index;
            _guid = guid;
        }

        #region 显示相关

        public string WindowTitle
        {
            get { return (string)GetValue(WindowTitleProperty); }
            set { SetValue(WindowTitleProperty, value); }
        }
        /// <summary>
        /// 显示图像
        /// </summary>
        /// <param name="image">
        /// </param>
        public void Display(HImage? image, bool freeImage = false)
        {
            Dispatcher.BeginInvoke(() =>
            {
                HImage2ImageSource(image, freeImage);
            }, DispatcherPriority.ApplicationIdle);
        }

        public void HImage2ImageSource(HImage? hImage, bool freeImage)
        {
            if (hImage?.IsInitialized() != true) return;
            try
            {
                if (hImage.CountChannels() == 3)
                {
                    hImage.GetImageSize(out int width, out int height);
                    PixelFormat pf = PixelFormats.Bgr32;
                    HImage hImage1 = hImage.InterleaveChannels("argb", "match", 0);
                    IntPtr intPtr = hImage1.GetImagePointer1(out string type, out int width1, out int height1);
                    int rawStride = (width * pf.BitsPerPixel) / 8;
                    _writeabBitmap = new(width, height, 96, 96, pf, null);
                    _writeabBitmap.WritePixels(new Int32Rect(0, 0, width, height), intPtr, width1 * height1, rawStride);
                    DisplayImage.Source = _writeabBitmap;
                    hImage1.Dispose();
                }
                else
                {
                    PixelFormat pf = PixelFormats.Gray8;
                    IntPtr intPtr = hImage.GetImagePointer1(out string type, out int width, out int height);
                    int rawStride = width * pf.BitsPerPixel / 8;
                    _writeabBitmap = new(width, height, 96, 96, pf, null);
                    _writeabBitmap.WritePixels(new Int32Rect(0, 0, width, height), intPtr, width * height, rawStride);
                    DisplayImage.Source = _writeabBitmap;

                }
            }
            catch (Exception ex)
            {
                return;
            }
            finally
            {
                if (freeImage)
                    hImage.Dispose();
            }
        }
        public void ResetWindow()
        {
            _scaleTransform.CenterX = 0; _scaleTransform.CenterY = 0;
            _scaleTransform.ScaleX = 1; _scaleTransform.ScaleY = 1;
            _translate.X = 0; _translate.Y = 0;
        }

        /// <summary>
        /// 设置流程名称前景色，用来显示相机状态
        /// </summary>
        /// <param name="color">
        /// </param>
        public void SetProg(Color color)
        {
            TbProName.Foreground = new SolidColorBrush(color);
        }

        #endregion 显示相关

        #region 图片缩放、平移

        private void CvDisplay_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            _isMove = false;
        }

        private void Grid_PreviewMouseMove(object sender, MouseEventArgs e)
        {
            TbImageSize.Text = $"{DisplayImage.ActualHeight},{DisplayImage.ActualWidth}";

            Point curPoint = e.GetPosition(CvDisplay);
            string str = $"行:{curPoint.Y:f0},列:{curPoint.X:f0}";

            if (_isMove && AllowMoveScale)
            {
                _translate.X += _scaleTransform.ScaleX * (curPoint.X - _startMovePoint.X);
                _translate.Y += (curPoint.Y - _startMovePoint.Y) * _scaleTransform.ScaleY;
            }
            string str1 = string.Empty;
            try
            {
                if (DispImage != null && DispImage is WriteableBitmap bitmap)
                {
                    int col = (int)curPoint.X;
                    int row = (int)curPoint.Y;
                    if (row < 0 || col < 0) return;
                    if (row > bitmap.PixelHeight || col > bitmap.PixelWidth) return;
                    byte[] pixels = new byte[bitmap.PixelHeight * bitmap.BackBufferStride];
                    bitmap.CopyPixels(pixels, bitmap.BackBufferStride, 0);
                    int id = row * bitmap.BackBufferStride + col * 4;
                    str1 = $"R:{pixels[id + 2]},G:{pixels[id + 1]},B:{pixels[id]}";
                }
                TbImagePoint.Text = str + " " + str1;
            }
            catch (Exception ex)
            {
            }
        }

        private void Grid_PreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e)
        {
            _isMove = true;
            _startMovePoint = e.GetPosition(CvDisplay);
        }

        private void Grid_PreviewMouseRightButtonUp(object sender, MouseButtonEventArgs e)
        {
            _isMove = false;
        }

        private void Grid_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
        {
            if (AllowMoveScale)
            {
                var point = e.GetPosition(CvDisplay);
                double scale = e.Delta * 0.0005;
                if ((_scaleTransform.ScaleX + scale) > 0)
                    _scaleTransform.ScaleX += scale;
                if ((_scaleTransform.ScaleY + scale) > 0)
                    _scaleTransform.ScaleY += scale;
                _translate.X -= point.X * scale;
                _translate.Y -= point.Y * scale;
            }
        }

        #endregion 图片缩放、平移
        /// <summary>
        /// 清除画板上的Visuals
        /// </summary>
        public void ClearVisual()
        {
            Dispatcher.BeginInvoke(() =>
            {
                CvDisplay1.ClearVisual();
            });
        }
        /// <summary>
        /// 清除画板上所有的ROI
        /// </summary>
        public void ClearAllROI()
        {
            CvDisplay2.Children.Clear();
        }

        public void DisplayCross(double row, double col, double size, double angle, Color color, double lineWidth)
        {
            Dispatcher.BeginInvoke(() =>
            {
                CvDisplay1.AddVisual(HObj2Draw.Cross2Draw(row, col, size, angle, color, lineWidth));
            });
        }

        /// <summary>
        /// 显示区域
        /// </summary>
        /// <param name="id">
        /// </param>
        /// <param name="region">
        /// </param>
        /// <param name="color">
        /// </param>
        /// <param name="isFill">
        /// </param>
        /// <param name="width">
        /// </param>
        public void DisplayRegion(HRegion region, Color color, bool isFill = false, double width = 1.0)
        {
            //if (_regionWatch.ElapsedMilliseconds > 300)
            {
                Dispatcher.BeginInvoke(() =>
                {
                    CvDisplay1.AddVisual(HObj2Draw.Region2Draw(region, new SolidColorBrush(color), isFill, width));
                });
                _regionWatch.Restart();
            }

        }

        /// <summary>
        /// 在对应的窗口上显示结果信息OK或NG
        /// </summary>
        /// <param name="id">
        /// </param>
        /// <param name="txt">
        /// </param>
        /// <param name="color">
        /// </param>
        /// <param name="fontsize">
        /// </param>
        public void DisplayResult(string txt, Color color, double fontsize = 20)
        {
            Dispatcher.BeginInvoke(() =>
            {
                TbInfo.Text = txt;
                TbInfo.FontSize = fontsize;
                TbInfo.Foreground = new SolidColorBrush(color);
            });
        }
        /// <summary>
        /// 在窗口显示文本Visual
        /// </summary>
        /// <param name="text"></param>
        /// <param name="color"></param>
        /// <param name="fontsize"></param>
        /// <param name="origin"></param>
        public void DisplayText(string text, Color color, double fontsize, Point origin)
        {
            //if (_textWatch.ElapsedMilliseconds > 300)
            {
                Dispatcher.BeginInvoke(() =>
                {
                    CvDisplay1.AddVisual(HObj2Draw.Text2Visual(text, color, fontsize, origin));
                });
                _textWatch.Restart();
            }

        }

        /// <summary>
        /// 在对应的窗口上显示图像个数及OK个数
        /// </summary>
        /// <param name="id">
        /// </param>
        /// <param name="txt">
        /// </param>
        /// <param name="color">
        /// </param>
        /// <param name="fontsize">
        /// </param>
        public void DisplayNum(string txt)
        {
            Dispatcher.BeginInvoke(() =>
            {
                TbYield.Text = txt;
            });
        }

        public void DisplayXLD(HXLDCont cont, Color color, double lineWidth, bool IsClose)
        {
            Dispatcher.BeginInvoke(() =>
            {
                CvDisplay1.AddVisual(HObj2Draw.Xld2Draw(cont, new SolidColorBrush(color), lineWidth, IsClose));
            });
        }

        public void DisplayXLD(List<HXLDCont> conts, Brush brush, double lineWidth, bool IsClosed)
        {
            Dispatcher.BeginInvoke(() =>
            {
                CvDisplay1.AddVisual(HObj2Draw.Xld2Draw(conts, brush, lineWidth, IsClosed));
            });
        }

        public void SaveStatus(string fileName, string imageFormat)
        {
            Dispatcher.BeginInvoke(() =>
            {
                SaveWindowContent(GdSave, fileName, imageFormat);
            });
        }

        

        private void SaveWindowContent(Panel source, string fileName, string imageFormat)
        {
            try
            {
                FrameworkElement elem = source;
                if (elem.ActualWidth <= 0 || elem.ActualHeight <= 0)
                {
                    return;
                }
                RenderTargetBitmap targetBitmap = new RenderTargetBitmap(
                                           (int)elem.ActualWidth,
                                           (int)elem.ActualHeight,
                                           96d,
                                           96d,
                                           PixelFormats.Pbgra32);

                targetBitmap.Render(source);

                if (imageFormat == "jpg")
                {
                    JpegBitmapEncoder encoder = new();
                    encoder.Frames.Add(BitmapFrame.Create(targetBitmap));
                    // save file to disk
                    using (FileStream fs = File.Open(fileName + $".{imageFormat}", FileMode.OpenOrCreate))
                    {
                        encoder.Save(fs);
                    }
                }
                else
                {
                    BmpBitmapEncoder encoder = new BmpBitmapEncoder();
                    encoder.Frames.Add(BitmapFrame.Create(targetBitmap));
                    // save file to disk
                    using (FileStream fs = File.Open(fileName + $".{imageFormat}", FileMode.OpenOrCreate))
                    {
                        encoder.Save(fs);
                    }
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.Message);
            }
        }


        public RenderTargetBitmap GetWindowContent()
        {
            try
            {
                FrameworkElement elem = GdSave;
                if (elem.ActualWidth <= 0 || elem.ActualHeight <= 0)
                {
                    return null;
                }
                RenderTargetBitmap targetBitmap = new RenderTargetBitmap(
                                           (int)elem.ActualWidth,
                                           (int)elem.ActualHeight,
                                           96d,
                                           96d,
                                           PixelFormats.Pbgra32);

                targetBitmap.Render(GdSave);
                return targetBitmap;
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.Message);
                return null;
            }
        }

        private void UserControl_MouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            _scaleTransform.ScaleX = 1;
            _scaleTransform.ScaleY = 1;
            _translate.X = 0;
            _translate.Y = 0;
        }

        double p1X = 0;
        double p1Y = 0;
        Point startPoint = new Point(0, 0);
        Point endPoint = new Point(0, 0);
        bool _isDrawDone = false;
        bool _canMoveEnd;
        private void CvDisplay2_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            if (_index == 0 || !CanDraw) return;

           


            switch (_index / 10)
            {
                case 1:
                    {
                        if (_index % 10 == 0)
                        {
                            var p = e.GetPosition(sender as Canvas);
                            p1X = p.X;
                            var line = new LineControl(this.CvDisplay2, p, Colors.Red, 200, false, _guid+"(1)");

                            _index++;
                            _rOIs.Add(line);
                            line.ROIChange = (s, e) =>
                            {
                                var l = s as LineControl;
                                var oldL = _rOIs.Find(m => m.ID == l.ID);
                                oldL = l;
                                var gu = l.ID.Split('(')[0];

                                var oldls = _rOIs.FindAll(m => m.ID.Split('(')[0] == l.ID.Split('(')[0]);
                                _actionDrawOver?.Invoke(oldls, gu);
                            };
                        }
                        else if (_index % 10 == 1)
                        {
                            var p = e.GetPosition(sender as Canvas);
                            var line = new LineControl(this.CvDisplay2, new Point(p1X,p.Y), Colors.Red, 200, false, _guid+"(2)");
                            _rOIs.Add(line);
                            _index = 0;
                            line.ROIChange = (s, e) =>
                            {
                                var l = s as LineControl;
                                var oldL = _rOIs.Find(m => m.ID == l.ID);
                                oldL = l;
                                var gu = l.ID.Split('(')[0];

                                var oldls = _rOIs.FindAll(m => m.ID.Split('(')[0] == l.ID.Split('(')[0]);
                                _actionDrawOver?.Invoke(oldls, gu);
                            };

                            MeasureResults.Add(new MeasureResult() { MeasureID = _guid,WaferName=MainWindow.CurWafer, ResultType = "水平线" });
                            var rois = _rOIs.FindAll(m => m.ID.Split('(')[0] == _guid);
                            _actionDrawOver?.Invoke(rois, _guid);
                        }
                        return;
                    }
                case 2:
                    {
                        if (_index % 10 == 0)
                        {
                            var p = e.GetPosition(sender as Canvas);
                            p1Y = p.Y;
                            var line = new LineControl(this.CvDisplay2, p, Colors.Red, 600, true, _guid + "(1)");

                            _index++;
                            _rOIs.Add(line);
                            line.ROIChange = (s, e) =>
                            {
                                var l = s as LineControl;
                                var oldL = _rOIs.Find(m => m.ID == l.ID);
                                oldL = l;
                                var gu = l.ID.Split('(')[0];

                                var oldls = _rOIs.FindAll(m => m.ID.Split('(')[0] == l.ID.Split('(')[0]);
                                _actionDrawOver?.Invoke(oldls, gu);
                            };
                        }
                        else if (_index % 10 == 1)
                        {
                            var p = e.GetPosition(sender as Canvas);
                            var line = new LineControl(this.CvDisplay2, new Point(p.X,p1Y), Colors.Red, 600, true, _guid + "(2)");
                            _rOIs.Add(line);
                            _index = 0;
                            line.ROIChange = (s, e) =>
                            {
                                var l = s as LineControl;
                                var oldL = _rOIs.Find(m => m.ID == l.ID);
                                oldL = l;
                                var gu = l.ID.Split('(')[0];

                                var oldls = _rOIs.FindAll(m => m.ID.Split('(')[0] == l.ID.Split('(')[0]);
                                _actionDrawOver?.Invoke(oldls, gu);
                            };

                            MeasureResults.Add(new MeasureResult() { MeasureID = _guid,WaferName = MainWindow.CurWafer, ResultType = "竖直线" });
                            var rois = _rOIs.FindAll(m => m.ID.Split('(')[0] == _guid);
                            _actionDrawOver?.Invoke(rois, _guid);
                        }
                        return;
                    }
                case 3:
                    {
                        if (_index % 10 == 0)
                        {
                            _isDrawDone = false;
                            startPoint = e.GetPosition(sender as Canvas);
                            _startLine = new Line()
                            {
                                X1 = startPoint.X - 200,
                                Y1 = startPoint.Y,
                                X2 = startPoint.X + 200,
                                Y2 = startPoint.Y,
                                Stroke = Brushes.Red,
                                StrokeThickness = 5
                            };

                            _line = new Line()
                            {
                                X1 = 0,
                                Y1 = 0,
                                X2 = 0,
                                Y2 = 0,
                                Stroke = Brushes.Red,
                                StrokeThickness = 5,
                                StrokeDashArray = new DoubleCollection() { 3, 3 }
                            };

                            (sender as Canvas)?.Children.Add(_startLine);
                            (sender as Canvas)?.Children.Add(_line);

                            _index++;
                        }
                        else if (_index % 10 == 1)
                        {
                            endPoint = e.GetPosition(sender as Canvas);
                            _endLine = new Line()
                            {
                                X1 = endPoint.X - 200,
                                Y1 = endPoint.Y,
                                X2 = endPoint.X + 200,
                                Y2 = endPoint.Y,
                                Stroke = Brushes.Red,
                                StrokeThickness = 5
                            };
                            _canMoveEnd = true;
                            (sender as Canvas)?.Children.Add(_endLine);

                            _index++;
                        }

                        else if (_index % 10 == 2)
                        {
                            _isDrawDone = true;
                            HOperatorSet.DistancePp(startPoint.Y, startPoint.X, endPoint.Y, endPoint.X, out HTuple distance);
                            Point point;
                            if (Math.Abs((Math.Abs(deg) - 0)) < 10 || Math.Abs((Math.Abs(deg) - 180)) < 10)
                                point = new Point(startPoint.X + 60, startPoint.Y - 150);
                            else
                                point = new Point(startPoint.X + 50, startPoint.Y + 50);

                            var mr = new MeasureResult() { Distance = distance.D * GlobalData.Instance.RatioParam.X50Ratio,WaferName=MainWindow.CurWafer, MeasureID = _guid, ResultType ="任意线段", TextPoint = point };
                            mr.AllLines = new();
                            mr.AllLines.Add(_startLine);
                            mr.AllLines.Add(_endLine);
                            mr.AllLines.Add(_line);
                            MeasureResults.Add(mr);
                            _actionDrawOver2?.Invoke(_guid);
                            _canMoveEnd = false;
                        }
                        return;
                    }

            }
        }

        Line _line, _startLine, _endLine, _endLine1;
        double deg = 0;
        private void CvDisplay2_MouseMove(object sender, MouseEventArgs e)
        {
            if (startPoint.X == 0 || startPoint.Y == 0 || _isDrawDone || !CanDraw) return;
            var p = e.GetPosition(sender as Canvas);

            _line.X1 = startPoint.X;
            _line.Y1 = startPoint.Y;
            _line.X2 = p.X;
            _line.Y2 = p.Y - 10;
            var _rotateAngle = Math.Atan2(_line.Y2 - _line.Y1, _line.X2 - _line.X1); //线当前的角度

            deg = (180 / Math.PI) * _rotateAngle;
            var _r1 = (deg - 90) * (Math.PI / 180);
            RotateLine(-200, 0, 200, 0, _r1, startPoint.X, startPoint.Y, out double snx1, out double sny1, out double snx2, out double sny2);
            _startLine.X1 = snx1;
            _startLine.Y1 = sny1;
            _startLine.X2 = snx2;
            _startLine.Y2 = sny2;

            if (endPoint.X == 0 || endPoint.Y == 0 || !_canMoveEnd) return;

            RotateLine(-200, 0, 200, 0, _r1, p.X, p.Y, out double enx1, out double eny1, out double enx2, out double eny2);
            _endLine.X1 = enx1;
            _endLine.Y1 = eny1;
            _endLine.X2 = enx2;
            _endLine.Y2 = eny2;
        }

        /// <summary>
        /// 旋转后的新直线
        /// </summary>
        /// <param name="dx1"></param>
        /// <param name="dy1"></param>
        /// <param name="dx2"></param>
        /// <param name="dy2"></param>
        /// <param name="r"></param>
        /// <param name="cx"></param>
        /// <param name="cy"></param>
        /// <param name="new_x1"></param>
        /// <param name="new_y1"></param>
        /// <param name="new_x2"></param>
        /// <param name="new_y2"></param>
        private void RotateLine(double dx1, double dy1, double dx2, double dy2, double r, double cx, double cy, out double new_x1, out double new_y1, out double new_x2, out double new_y2)
        {
            // 计算旋转后的坐标
            double cosAngle = Math.Cos(r);
            double sinAngle = Math.Sin(r);

            // 计算旋转后的坐标偏移
            double new_dx1 = dx1 * cosAngle - dy1 * sinAngle;
            double new_dy1 = dx1 * sinAngle + dy1 * cosAngle;

            // 计算新线段的起点坐标
            new_x1 = cx + new_dx1;
            new_y1 = cy + new_dy1;

            // 计算旋转后的坐标偏移
            double new_dx2 = dx2 * cosAngle - dy2 * sinAngle;
            double new_dy2 = dx2 * sinAngle + dy2 * cosAngle;

            // 计算新线段的终点坐标
            new_x2 = cx + new_dx2;
            new_y2 = cy + new_dy2;
        }
    }
}